﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ToDoListLab
{
    public partial class frmToDoList : Form
    {
        #region Private Members
        private DataSet dsTodoList;
        private readonly string xsdFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ToDoList.xsd");
        private readonly string xmlFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ToDoList.xml");
        #endregion

        /// <summary>
        /// Load information
        /// </summary>
        void PopulateDataSet()
        {
            CreateSchema();
            // load data
            if (File.Exists(xmlFile))
            {
                dsTodoList.ReadXml(xmlFile, XmlReadMode.IgnoreSchema);
            }
        }

        /// <summary>
        /// Create schema
        /// </summary>
        void CreateSchema()
        {
            // create dataset
            dsTodoList = new DataSet("ToDoList");
            // adding data tables
            DataTable dtTask = dsTodoList.Tables.Add("Tasks");
            // addin columns
            DataColumn pkTask = dtTask.Columns.Add("TaskId", typeof(int));
            pkTask.AutoIncrement = true;
            pkTask.AutoIncrementSeed = -1;
            pkTask.AutoIncrementStep = -1;
            dtTask.Columns.Add("Name", typeof(string));
            dtTask.Columns.Add("Sequence", typeof(int));
            // add constraints
            dtTask.PrimaryKey = new DataColumn[] { pkTask };
            // Mappint Type = attribute
            dtTask.Columns["TaskId"].ColumnMapping = MappingType.Attribute;
            dtTask.Columns["Name"].ColumnMapping = MappingType.Attribute;
            dtTask.Columns["Sequence"].ColumnMapping = MappingType.Attribute;

            // create data table Person
            DataTable dtPerson = dsTodoList.Tables.Add("Persons");
            dtPerson.Columns.Add("PersonId", typeof(string));
            dtPerson.Columns.Add("LastName", typeof(string));
            dtPerson.Columns.Add("MiddleName", typeof(string));
            dtPerson.Columns.Add("Name", typeof(string));
            dtPerson.Columns.Add("Phone", typeof(string));
            dtPerson.PrimaryKey = new DataColumn[] { dtPerson.Columns["PersonId"] };
            // ColumnMapping = MappingType.Attribute
            dtPerson.Columns["PersonId"].ColumnMapping = MappingType.Attribute;
            dtPerson.Columns["LastName"].ColumnMapping = MappingType.Attribute;
            dtPerson.Columns["MiddleName"].ColumnMapping = MappingType.Attribute;
            dtPerson.Columns["Name"].ColumnMapping = MappingType.Attribute;
            dtPerson.Columns["Phone"].ColumnMapping = MappingType.Attribute;

            // create data table Person Tasks
            DataTable dtPersonTasks = dsTodoList.Tables.Add("PersonTasks");
            dtPersonTasks.Columns.Add("PersonId", typeof(string));
            dtPersonTasks.Columns.Add("TaskId", typeof(int));
            dtPersonTasks.Columns.Add("Completed", typeof(bool));
            dtPersonTasks.PrimaryKey = new DataColumn[] { dtPersonTasks.Columns["PersonId"], dtPersonTasks.Columns["TaskId"] };
            // ColumnMapping = MappingType.Attribute
            dtPersonTasks.Columns["PersonId"].ColumnMapping = MappingType.Attribute;
            dtPersonTasks.Columns["TaskId"].ColumnMapping = MappingType.Attribute;
            dtPersonTasks.Columns["Completed"].ColumnMapping = MappingType.Attribute;

            // add relationship
            dsTodoList.Relations.Add("tasks_persons", new DataColumn[] { dtTask.Columns["TaskId"] }, new DataColumn[] { dtPersonTasks.Columns["TaskId"] });
            dsTodoList.Relations.Add("persons_tasks", dtPerson.Columns["PersonId"], dtPersonTasks.Columns["PersonId"]);

            // save schema
            dsTodoList.WriteXmlSchema(xsdFile);
        }

        /// <summary>
        /// Load relationship with data from parent rows
        /// </summary>
        /// <returns></returns>
        DataTable LoadTasksPersons()
        {
            DataTable dt = new DataTable("PersonsTasks");
            dt.Columns.Add("TaskId", typeof(int));
            dt.Columns.Add("TaskName", typeof(string));
            dt.Columns.Add("PersonId", typeof(int));
            dt.Columns.Add("PersonName", typeof(string));
            dt.Columns.Add("PersonMiddleName", typeof(string));
            dt.Columns.Add("PersonLastName", typeof(string));
            dt.Columns.Add("Completed", typeof(bool));

            if (dsTodoList != null && dsTodoList.Relations.Count != 0)
            {
                foreach (DataRow row in dsTodoList.Relations["tasks_persons"].ChildTable.Rows)
                {
                    DataRow person = row.GetParentRow("persons_tasks");
                    dt.Rows.Add(new object[]{
                        row["TaskId"],
                        row.GetParentRow("tasks_persons")["Name"],
                        row["PersonId"],
                        person["Name"],
                        person["MiddleName"],
                        person["LastName"],
                        row["Completed"]
                    });
                }
            }
            return dt;
        }

        DataTable ApplyFilter()
        {
            if (dgResults.DataSource != null)
            {
                DataView dvResult = new DataView((DataTable)dgResults.DataSource);
                string filter = "";
                filter += chkTaskId.Checked ? string.Format("TaskId = {0}", txtTaskId.Text.Trim()) : "";

                if (chkTaskName.Checked)
                {
                    if (filter.Length > 0)
                        filter += " AND ";
                    filter += string.Format("TaskName LIKE '{0}%'", txtTaskName.Text.Trim());
                }

                if (chkPersonId.Checked)
                {
                    if (filter.Length > 0)
                        filter += " AND ";

                    filter += string.Format("PersonId = {0}", txtPersonId.Text.Trim());
                }

                if (chkPersonName.Checked)
                {
                    if (filter.Length > 0)
                        filter += " AND ";

                    filter += string.Format("PersonName LIKE '{0}%'", txtPersonName.Text.Trim());
                }
                // filtering
                dvResult.RowFilter = filter;
                return dvResult.ToTable();
            }
            return null;
        }

        public frmToDoList()
        {
            InitializeComponent();
        }

        private void frmToDoList_Load(object sender, EventArgs e)
        {
            // load data
            PopulateDataSet();

            // binding data sources
            dgTask.DataSource = dsTodoList;
            dgTask.DataMember = "Tasks";

            dgPerson.DataSource = dsTodoList;
            dgPerson.DataMember = "Persons";

            dgPersonTask.DataSource = dsTodoList;
            dgPersonTask.DataMember = "Tasks.tasks_persons";

            dgResults.AutoGenerateColumns = true;
            dgResults.DataSource = LoadTasksPersons();
        }

        private void frmToDoList_FormClosing(object sender, FormClosingEventArgs e)
        {
            // save xml
            dsTodoList.WriteXml(xmlFile, XmlWriteMode.DiffGram);
        }

        private void chkPersonId_CheckedChanged(object sender, EventArgs e)
        {
            txtPersonId.Enabled = chkPersonId.Checked;
            txtPersonId.Focus();
        }

        private void chkPersonName_CheckedChanged(object sender, EventArgs e)
        {
            txtPersonName.Enabled = chkPersonName.Checked;
            txtPersonName.Focus();
        }

        private void chkTaskId_CheckedChanged(object sender, EventArgs e)
        {
            txtTaskId.Enabled = chkTaskId.Checked;
            txtTaskId.Focus();
        }

        private void chkTaskName_CheckedChanged(object sender, EventArgs e)
        {
            txtTaskName.Enabled = chkTaskName.Checked;
            txtTaskName.Focus();
        }

        private void btnApplyFilter_Click(object sender, EventArgs e)
        {
            dgResults.DataSource = ApplyFilter();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            dgResults.DataSource = LoadTasksPersons();
        }
    }
}
